#include "highlighter.h"


/* Parentheses Matching - Depuis l'exemple du magazine Qt Quaterly */
QVector<ParenthesisInfo *> TextBlockData::parentheses() {
    return m_parentheses;
}

void TextBlockData::insert(ParenthesisInfo *info) {
    int i = 0;
    while (i < m_parentheses.size() && info->position > m_parentheses.at(i)->position)
        ++i;
    m_parentheses.insert(i, info);
}


/* Highlighter du ragnascript */

Highlighter::~Highlighter() {  }

QStringList Highlighter::importPatterns(const QString &fileName)
{
    QStringList words;

    QFile file(fileName);
    if (!file.open(QFile::ReadOnly))
        return words; /* Liste vide */

    while (!file.atEnd())
    {
        QByteArray line = file.readLine();
        if (!line.isEmpty())
            words << "\\b"+line.trimmed()+"\\b";
    }

    file.close();
    return words;
}

Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent)
{
    HighlightingRule rule;

    numberFormat.setForeground(QColor(255, 120, 0));
    rule.pattern = QRegExp("[0-9]");
    rule.format = numberFormat;
    highlightingRules.append(rule);

    labelFormat.setForeground(Qt::darkGreen);
    labelFormat.setFontWeight(QFont::Bold);
    rule.pattern = QRegExp("(On|L_)\\w+:"); /* Label type Onxxx: et L_xxx: */
    rule.format = labelFormat;
    highlightingRules.append(rule);

    keywordFormat.setForeground(Qt::darkBlue);
    keywordFormat.setFontWeight(QFont::Bold);

    keywordPatterns = importPatterns(":/wordlist.txt");

    foreach (const QString &pattern, keywordPatterns)
    {
        rule.pattern = QRegExp(pattern, Qt::CaseInsensitive);
        rule.format = keywordFormat;
        highlightingRules.append(rule);
    }

    functionFormat.setFontItalic(true);
    functionFormat.setForeground(Qt::blue);
    rule.pattern = QRegExp("\\b[A-Za-z_]+[0-9]*(?=\\()");
    rule.format = keywordFormat; /* Les fonctions utilisent la même colorisation que les commandes classiques */
    highlightingRules.append(rule);

    quotationFormat.setForeground(Qt::red);
    rule.pattern = QRegExp("\"[^\"]*\"");
    rule.format = quotationFormat;
    highlightingRules.append(rule);

    commentStartExpression = QRegExp("/\\*");
    commentEndExpression = QRegExp("\\*/");

    singleLineCommentFormat.setForeground(Qt::darkGreen);
    rule.pattern = QRegExp("//[^\n]*");
    rule.format = singleLineCommentFormat;
    highlightingRules.append(rule);

    multiLineCommentFormat.setForeground(Qt::gray);
}


void Highlighter::highlightBlock(const QString &text)
{
    QVector<int> indexesList;

    foreach (const HighlightingRule &rule, highlightingRules)
    {
        /* V1 -- normale */
        QRegExp expression(rule.pattern);
        int index = expression.indexIn(text);
        while (index >= 0)
        {
            int length = expression.matchedLength();
            setFormat(index, length, rule.format);
            index = expression.indexIn(text, index + length);
        }


        /* V2 -- QtConcurrentRun

        indexes.setFuture(QtConcurrent::run(this, &Highlighter::getIndexes, text, rule));

        // Ligne qui provoque le segfault : (oO)
        while(!indexes.isFinished()) { qApp->processEvents(); }
        // Visiblement un problème de partage de l'UI... [TO-FIX]

        indexesList = indexes.result();
        for(int i = 0; i < indexesList.size(); i+=2)
            setFormat(indexesList.at(i), indexesList.at(i+1), rule.format);

         V2 ------------------ */
    }

    setCurrentBlockState(0);

    int startIndex = 0;
    if (previousBlockState() != 1)
        startIndex = commentStartExpression.indexIn(text);

    while (startIndex >= 0)
    {
        int endIndex = commentEndExpression.indexIn(text, startIndex);
        int commentLength;

        if (endIndex == -1)
        {
            setCurrentBlockState(1);
            commentLength = text.length() - startIndex;
        }

        else
        {
            commentLength = endIndex - startIndex + commentEndExpression.matchedLength();
        }

        setFormat(startIndex, commentLength, multiLineCommentFormat);
        startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
    }

    /* Parentheses/braces matching */

    TextBlockData *data = new TextBlockData;

    int leftPos = text.indexOf('(');
    while (leftPos != -1)
    {
        ParenthesisInfo *info = new ParenthesisInfo;
        info->character = '(';
        info->position = leftPos;

        data->insert(info);
        leftPos = text.indexOf('(', leftPos+1);
    }

    leftPos = text.indexOf('{');
    while (leftPos != -1)
    {
        ParenthesisInfo *info = new ParenthesisInfo;
        info->character = '{';
        info->position = leftPos;

        data->insert(info);
        leftPos = text.indexOf('{', leftPos+1);
    }

    int rightPos = text.indexOf(')');
    while (rightPos != -1)
    {
        ParenthesisInfo *info = new ParenthesisInfo;
        info->character = ')';
        info->position = rightPos;

        data->insert(info);
        rightPos = text.indexOf(')', rightPos+1);
    }

    rightPos = text.indexOf('}');
    while (rightPos != -1)
    {
        ParenthesisInfo *info = new ParenthesisInfo;
        info->character = '}';
        info->position = rightPos;

        data->insert(info);
        rightPos = text.indexOf('}', rightPos+1);
    }

    setCurrentBlockUserData(data);
}

/* méthode threadée (TODO : fixer le segfault :°)...)
QVector<int> Highlighter::getIndexes(const QString &text, const HighlightingRule &rule)
{
    QRegExp expression(rule.pattern);
    QVector<int> indexesList;

    int index = expression.indexIn(text);

    while (index >= 0)
    {
        indexesList.append(index);
        int length = expression.matchedLength();
        indexesList.append(length);
        index = expression.indexIn(text, index + length);
    }

    return indexesList;
}
*/
